This Technical Note describes the routines and internal structures needed to design a printer driver for the Apple IIgs system, and you should use this Note with the Apple IIgs Toolbox Reference manuals. An overview and associated parameters for each of the printer driver routines are in the Print Manager chapter, and you should refer to these for a complete picture.
Changed since March 1990: Added corrections and further descriptions.
There are two printing modes: immediate and deferred.
The user can install new printer drivers into the system by copying a printer driver file into a subdirectory called DRIVERS within the SYSTEM subdirectory. The printer driver file must be of type $BB and have an auxiliary type of $0001.
A printer driver must support the following calls:
Printer drivers may support the following calls if they use the new driver structure outlined below:
StartOfNewDriver START
dc i2'0' ; new style driver
dc i2'(ListEnd-PrDriverList)/4' ; count
jmp (PrDriverList,x)
PrDriverList dc a4'PrDefault'
dc a4'PrValidate'
dc a4'PrStlDialog'
dc a4'PrJobDialog'
dc a4'PrDriverVer'
dc a4'PrOpenDoc'
dc a4'PrCloseDoc'
dc a4'PrOpenPage'
dc a4'PrClosePage'
dc a4'PrPicFile'
dc a4'InvalidRoutine'
dc a4'PrError'
dc a4'PrSetError'
dc a4'GetDeviceName'
dc a4'PrPixelMap'
dc a4'PrGetPrinterSpecs'
dc a4'PrGetPgOrientation'
ListEnd anop
In previous versions of this Note, the PrPixelMap and PrDriverVer entries were reversed.
Note that when using the above technique, you're using a 16-bit jump into a table of 24-bit addresses. If all your entry points are in the same segment, this is not a problem.
If your routines' entry points are not all in the same segment, you need a dispatching routine like the following:
StartOfNewDriver START
dc i2 '0' ; new style driver
dc i2 '(ListEnd-PrDriverList)/4' ; count
lda PrDriverList+2,x
sep #$20
pha ; push high byte of
; address
rep #$20
lda PrDriverList,x
dec a ; decrement low 2
; bytes only
pha ; push modified low
; word of address
rtl ; transfer to the
; routine
See Apple IIgs Technical Note #90, 65816 Tips and Pitfalls, for a discussion of dispatching with RTL.
When one of your routines is ready to exit, it needs to remove the input parameters from the stack, leaving the result space (if any) and the two RTL addresses. Set the accumulator and the carry flag to reflect any error you are returning, then perform an RTL.
If there are N bytes of input parameters to remove, use something like the following. This code assumes that the error code is in the accumulator.
tay ; keep error code in Y
; temporarily
lda 5,s
sta N+5,s
lda 3,s
sta N+3,s
lda 1,s
sta N+1,s
tsc
clc
adc #N
tcs
tya ; get error code
cmp #1 ; set carry if error
; is not zero
rtl
Figure 1 diagrams the stack just before exiting the print driver:
|
| Previous Contents
|___________________
|
| Results (if any)
|___________________
|
| RTL2 (3 bytes)
|___________________
|
| RTL1 (3 bytes)
|___________________
<-- Stack Pointer
Figure 1 - Stack Prior to Exiting the Print Driver
You should do an RTL with the contents of the flags and registers set appropriately. (See the Return from Call section of the "Using The Apple Tools" chapter of the Apple IIgs Toolbox Reference.)
Since application programs often need to fiddle with parts of the print record (i.e., the values in the style subrecord), we have defined ways for applications to interpret the print record, and specifically the style subrecord.
iDev, the first word of the printer information subrecord, has two defined values for third-party printer drivers. A value of $8001 indicates a dot-matrix printer while a value of $8003 indicates a laser printer.
A value of $8001 indicates that fields of the style subrecord should be interpreted as they are by the ImageWriter driver, as documented in the Apple IIgs Toolbox Reference. The first seven bits (0-6) of wDev are defined as for the ImageWriter driver. Bits 7-11 are reserved for Apple's use and must be set to zero. Bits 12-15 may be used by third-party printer drivers as necessary; these bits are set to zero in Apple's drivers.
A value of $8003 indicates that fields of the style subrecord should be interpreted as they are by the LaserWriter driver. The first four bits (0-3) of wDev are defined as for the LaserWriter driver. Bits 4-11 are reserved for Apple's use and must be set to zero. Bits 12-15 may be used by third-party printer drivers as necessary; these bits are set to zero in Apple's drivers.
If an application wishes to take advantages of specific features of a third-party printer driver, it has to know that it is dealing with that driver. Since all drivers look pretty much alike, the Print Manager allows you to ask for the name of the currently selected printer driver. An application may make the Print Manager call PMGetPrinterName, which is documented in Volume 3 of the Toolbox Reference. The Print Manager returns the name of the currently selected printer in a Pascal (length byte) string. The name returned is the name of the file from which the driver was loaded. If you intend to use this method to identify a driver, you must inform users not to rename the Printer Driver file on the boot disk.
For alternate driver identification, Developer Technical Support assigns new iDev values if you feel it is absolutely necessary for your driver. Please keep in mind, however, that no application knows how to interpret style records for non-standard iDev values, and that Apple does not publish such interpretations.
Your printer driver handles the following calls:
Note: The following are items typically found in printer style dialogs:
Every printer style dialog should have an OK button (default) and a Cancel button.
Note: When calling other routines in your printer driver (like PrValidate), be sure to do so through the Tool Dispatcher ($E10000 or $E10004) so any necessary patches have an opportunity to execute.
Note: The following are items typically found in printer job dialogs:
Every printer job dialog should have an OK button (default) and a Cancel button.
Note: When calling other routines in your printer driver (like PrValidate), be sure to do so through the Tool Dispatcher ($E10000 or $E10004) so any necessary patches have an opportunity to execute.
You can choose to print the pixel map in any convenient fashion; one convenient way is to allocate a new print record and call your normal printing routines. This method is outlined below.
(also known as PrChanged)
This routine will be called by the Print Manager when your driver is first loaded so a network port driver can find devices of your type. Applications should not make this call. When this routine will be called is not guaranteed; you can't use this as a substitute for a startup call.
Note: The internal version number is stored major byte, minor byte i.e., $0103 represents version 1.3)
The value returned for PrinterType should be the driver's iDev value.
To print in the immediate mode, you need to install procedures which cause printing when you make QuickDraw II calls (as noted in PrOpenPage). This section describes the structure and parameters for these routines.
The basic idea is that your driver replaces low-level QuickDraw II routines with pointers to your own routines. For example, when someone wants QuickDraw II to draw some text (say with DrawString), QuickDraw II calls your low-level routine to draw the text. You can then print the text instead.
To install the immediate mode procedures, first create a procedure table for sixteen entries (16*4 bytes) and fill it with the standard procedures by calling SetStdProcs. Once you have the standard procedures, install the addresses of your replacement procedures into it and call SetGrafProcs. Installing your procedure addresses causes the appropriate QuickDraw II calls to call your procedures, which, in turn, perform the actual printing.
The routines that need to be written are known as QuickDraw II "bottleneck procedures." For most dot-matrix printer drivers, the one of most concern when writing immediate mode procedures is StdText. If your target device has an alternate page imaging language, you may wish to print entirely in immediate mode. In this case, you want to intercept most of the bottleneck procedures. Apple IIgs Technical Note #34, Low-Level QuickDraw II Routines, contains information on how to install these procedures. The sample code which follows shows how to replace StdPixels and StdText.
;*****************************************************************
;** Example of Immediate Mode Printer Procedures. **
;*****************************************************************
Immedprocs Start
SrcRect equ $DC
SrcLocInfo equ $CC
DrawVerb equ $38
TextPtr equ $da
TextLength equ $d8
CharToDraw equ $d6
;------------------------------------------------------------------
;
; StdPixels Procedure (Prints Pixel maps)
;
;------------------------------------------------------------------
Pixel Entry
phb ;save data bank reg on stack
phk ;get program bank reg.
plb ;use as data bank reg.
lda iPrErr ;get errors
beq Continue ;branch if none
brl ExitPixel ;branch if errors
Continue anop
;This gets the source rectangle and stores it at PixelRect
ldx #6
MoveSrc lda SrcRect,x
sta PixelRect,x
dex
dex
bpl MoveSrc
;This gets the source LocInfo and stores it at PixelLoc
ldx #16-2
MoveLI lda SrcLocInfo,x
sta PixelLoc,x
dex
dex
bpl MoveLI
pushlong #PixelLoc ;push pointer to LocInfo
pushlong #PixelRect ;push pointer to rectangle
;++++++++++++++++++++++
; Insert code here to print a pixel map
; INPUT: PixelLoc LONG, Pointer to pixel LocInfo
; PixelRect LONG, Pointer to pixels BoundsRect
; SP->
;++++++++++++++++++++++
Exitpixel lda #0 ;return with no errors
clc
plb ;restore data bank
rtl ;return with long
PixelLoc ds 16 ;pixel LocInfo
PixelRect ds 8 ;pixel rectangle
;------------------------------------------------------------------
;
; StdText Procedure (Prints Standard Text)
;
;------------------------------------------------------------------
StdText Entry
phb ;save data bank reg on stack
phk ;get program bank reg.
plb ;use as data bank reg.
pushlong #PenPos
_GetPen ;current pen pos. -> PenPos
;++++++++++++++++++++++
; Insert Code Here to move the printers head to the corresponding
; PenPos position (if needed).
;++++++++++++++++++++++
pushword #0 ;space for textwidth
;(for call to _TextWidth)
lda DrawVerb ;get DrawVerb
beq DoCar ;if DrawVerb=0 then DoCar
cmp #1
beq Dotext2 ;if DrawVerb=1 then Dotext2
;
;We get here if it's a "C" string (DrawVerb=2)
;
DoCstring anop
sep #$20
longa off
;Search down through string looking for terminator to calc. length
ldy #0
KeepLooking lda [TextPtr],y
beq TheEnd
iny
bra KeepLooking
TheEnd rep #$20
longa on
lda TextPtr+2
pha ;push the pointer to string
lda Textptr
pha
phy ;push the length of sting
bra Common
;
;We get here if it's just one character (DrawVerb=0)
;
DoCar anop
pushword #0
tdc
clc
adc #CharToDraw ;calculate addr. of char.
pha ;push addr. of character
pushword #1 ;push length of one char.
bra Common
;
;We get here if it's a string of text (DrawVerb=1)
;
DoText2 anop
lda TextPtr+2
pha ;push pointer to the string
lda Textptr
pha
lda TextLength
pha ;push the strings length
Common lda 5,s ;Dup the last 3 words of
pha ;the stack (for _TextWidth)
lda 5,s
pha
lda 5,s
pha
;++++++++++++++++++++++
; Insert code here to print the text
;
; INPUT: TextPointer LONG, Pointer to text to print
; TextLength WORD, No. of bytes to print
; SP->
;++++++++++++++++++++++
_TextWidth ;get the texts width (DH)
pushword #0 ;set (DV)=0
_Move ;move current pen location
ExitText lda #0 ;return with no errors
clc
plb ;restore data bank
rtl ;returnith long
PenPos ds 4 ;pen position
end
This and all of the other Apple II Technical Notes have been converted to HTML by Aaron Heiss as a public service to the Apple II community, with permission by Apple Computer, Inc. Any and all trademarks, registered and otherwise, are properties of their owners.
PostScript is a registered trademark of Adobe Systems Incorporated.